/**
 *******************************************************************************
 * @brief       Provide a brief description of the module here (Single line).
 * 
 * @author      Ashwin
 * 
 * @file        PalDs1307.c
 * 
 * @version
 * 
 * @date        Feb 21, 2012 7:12:33 PM
 * 
 * @details     Provide a detailed description of the module here (Multi-line).
 * 
 * @pre         Mention any preconditions required to use this module.
 * 
 * @bug         List any bugs in this module.
 * 
 * @note        List any odd modes while using this module.
 * 
 * @warning     List any warnings against using the objects of this module.
 *******************************************************************************
 * @copyright 2012
 * <a href="http://www.afflatustech.com">Afflatus Techtronics</a>
 * and <a href="http://www.ashwinvijayakumar.co.nr">Ashwin Vijayakumar</a>
 * @n@n
 * This work is licensed under the Creative Commons
 * Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy
 * of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or
 * send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain
 * View, California, 94041, USA.
 *******************************************************************************
 */

/**@cond -----------------------------------------------------------------------
 * Includes section
 * Add all #include here.
 * ----------------------------------------------------------------- @endcond */

/**@cond System headers -------------------------------------------- @endcond */
#include <i2c.h>

/**@cond Local headers --------------------------------------------- @endcond */
#include "PalDs1307.h"
#include "time.h"

/**@cond -----------------------------------------------------------------------
 * typedef section (File scope)
 * Add typedef's with file scope here.
 * Capitalization: Upper_Camel_Case.
 * Declare typedef's with project scope in Ds1307.h.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Constants section (File scope)
 * Add all constants with file scope here.
 * Capitalization: ALL_CAPS.
 * Note that all constants listed here are limited to this file scope.
 * For project wide scope, declare constants in Ds1307.h.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Macros section (File scope)
 * Add all macros with file scope here.
 * Capitalization: ALL_CAPS.
 * Note that all macros listed here are limited to this file scope.
 * For project wide scope, declare macros in Ds1307.h.
 * ----------------------------------------------------------------- @endcond */

#define PAL_DS1307_BCD2INT(BCD_VALUE)       (uint8)( ((BCD_VALUE >> 4) * 10) + (BCD_VALUE % 16) )

#define PAL_DS1307_INT2BCD(INT_VALUE)       (int)( ((INT_VALUE/10) << 4) + (INT_VALUE % 10) )

/**@cond -----------------------------------------------------------------------
 * Global variables section (File scope)
 * Add global variables with file scope here. 
 * Capitalization: lower_case.
 * Declare them with 'static' keyword.
 * ----------------------------------------------------------------- @endcond */

static PalDs1307_AmPmType                  PalDs1307_AmPm;

/**@cond -----------------------------------------------------------------------
 * Global variables section (Project scope)
 * PROJECT SCOPE G-VARIABLES ARE LIKE FORBIDDEN FRUIT. REFRAIN FROM USING THEM, 
 * DECLARE FILE SCOPE G-VARIABLES INSTEAD AND DEFINE GETTER/SETTER METHODS TO 
 * ACCESS THEM.
 * Add global variables with project scope here. 
 * Capitalization: lower_case.
 * Declare them without 'static' keyword.
 * Also declare these variables in Ds1307.h with 'extern' keyword.
 * ----------------------------------------------------------------- @endcond */

static I2c_AddressType I2c_Ds1307Address        = 0xD0;

/**@cond -----------------------------------------------------------------------
 * Function prototypes section (File scope)
 * Add prototypes for all functions with file scope here. 
 * Capitalization: lower_Camel_Case.
 * Declare them with 'static' keyword.
 * For functions with project scope, declare the function prototype in 
 * Ds1307.h without 'static' keyword.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Getter/setter method section (Project scope)
 * Define getter/setter methods to provide project scope global access to file 
 * scope global variables. (AVOID USING THESE IF YOU HAVE THROUGHPUT ISSUES).
 * Capitalization: get_Camel_Case/is_Camel_Case/set_Camel_Case.
 * Declare the prototype for these functions in Ds1307.h. 
 * ----------------------------------------------------------------- @endcond */

PalDs1307_AmPmType
get_PalDs1307_AmPm (void)
{
  return(PalDs1307_AmPm);
}

void
set_PalDs1307_AmPm (PalDs1307_AmPmType ampm)
{
  PalDs1307_AmPm = ampm;
}

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 25, 2012, 2:17:08 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

uint8
PalDs1307_ByteRead (PalDs1307_AddressType Ds1307Address)
{
  uint8 DataByte = E_NOT_OK;

  /* ---- Dummy write ------------------------------------------------------- */
  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(Ds1307Address);

  /* ---- Actual read operation starts here --------------------------------- */
  /* Send restart command */
  RestartI2C();

  /* Send device address with Read command */
  WriteI2C(I2c_Ds1307Address | I2C_READ_WRITE_MSK);

  /* Read data stream from SDA */
  DataByte = getcI2C();

  /* Send Stop command */
  StopI2C();

  return (DataByte);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 23, 2012, 7:58:27 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_ByteWrite (PalDs1307_AddressType Ds1307Address, uint8 DataByte)
{
  Std_ReturnType retVal = E_NOT_OK;

  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(Ds1307Address);

  /* Write a single byte to the I2C bus */
  putcI2C(DataByte);

  /* Send Stop command */
  StopI2C();

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          void function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 22, 2012, 7:09:34 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

void
PalDs1307_Init (PalDs1307_ConfigType* PalDs1307_ConfigPtr)
{
#if 0
  /* Convert time and date to BCD */
  PalDs1307_ConfigPtr->SecondsReg.bits.seconds     = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->SecondsReg.bits.seconds);
  PalDs1307_ConfigPtr->MinutesReg.bits.minutes     = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->MinutesReg.bits.minutes);
  PalDs1307_ConfigPtr->HoursReg.bits.hours         = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->HoursReg.bits.hours);
  PalDs1307_ConfigPtr->DayReg.bits.day             = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->DayReg.bits.day);
  PalDs1307_ConfigPtr->DateReg.bits.date           = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->DateReg.bits.date);
  PalDs1307_ConfigPtr->MonthReg.bits.month         = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->MonthReg.bits.month);
  PalDs1307_ConfigPtr->YearReg                     = PAL_DS1307_INT2BCD(PalDs1307_ConfigPtr->YearReg);
  PalDs1307_ConfigPtr->Reserved                    = NULL;
#endif

  /* Ensure that 'hours', 'AM/PM' and reserved' bits are cleared */
  PalDs1307_ConfigPtr->HoursReg.bits.hours = 0;
  PalDs1307_ConfigPtr->HoursReg.bits.ampm = 0;
  PalDs1307_ConfigPtr->HoursReg.bits.reserved_8 = 0;

  /* Set Hour Mode and AM/PM config */
  PalDs1307_ByteWrite(0x02, PalDs1307_ConfigPtr->HoursReg.byte);

  /* Set RS, SQWE and OUT config */
  PalDs1307_ByteWrite(0x07, PalDs1307_ConfigPtr->ControlReg.byte);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 25, 2012, 2:12:36 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_SetHourMode (PalDs1307_HourModeType PalDs1307_HourMode)
{
  Std_ReturnType retVal = E_NOT_OK;

  /* Read DS1307's Hours Register */
  PalDs1307_HourRegType PalDs1307_HourRegTemp = PalDs1307_ByteRead(0x02);

  /* Update Mode bit */
  PalDs1307_HourRegTemp.bits.ampm = PalDs1307_HourMode;

  /* Hours value must be reentered after changing mode bit */
  PalDs1307_ByteWrite(0x02, PalDs1307_HourRegTemp.byte);

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 23, 2012, 8:19:33 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_SetTime (PalDs1307_BreakdownTimeType* TimePtr)
{
  Std_ReturnType retVal = E_NOT_OK;
  PalDs1307_TimekeeperRegType PalDs1307_TimekeeperRegTemp;

  /* Read Hour Mode (12h/24h) from chip */
  PalDs1307_TimekeeperRegTemp.HoursReg.byte = PalDs1307_ByteRead (I2c_Ds1307Address);

  if(_12_HOUR == PalDs1307_TimekeeperRegTemp.HoursReg.bits.mode)
    { /* If set as 12H mode, update AM/PM from file scope AM/PM variable */
      PalDs1307_TimekeeperRegTemp.HoursReg.bits.ampm = get_PalDs1307_AmPm();
    }
  else
    { /* If 24H mode, clear AM/PM bit in the chip's Hour Reg */
      PalDs1307_TimekeeperRegTemp.HoursReg.bits.ampm = (PalDs1307_AmPmType)0;
    }

  PalDs1307_TimekeeperRegTemp.SecondsReg.bits.seconds     = PAL_DS1307_INT2BCD(TimePtr->tm_sec);
  PalDs1307_TimekeeperRegTemp.MinutesReg.bits.minutes     = PAL_DS1307_INT2BCD(TimePtr->tm_min);
  PalDs1307_TimekeeperRegTemp.HoursReg.bits.hours         = PAL_DS1307_INT2BCD(TimePtr->tm_hour);
  PalDs1307_TimekeeperRegTemp.DayReg.byte                 = NULL;

  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(0x00);

  /* Stream data bytes on SDA line */
  putsI2C(&PalDs1307_TimekeeperRegTemp.SecondsReg.byte);

  /* Send Stop command */
  StopI2C();

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 25, 2012, 10:48:39 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_SetDate (PalDs1307_BreakdownTimeType* TimePtr)
{
  Std_ReturnType retVal = E_NOT_OK;
  PalDs1307_TimekeeperRegType PalDs1307_TimekeeperRegTemp;

  PalDs1307_TimekeeperRegTemp.DayReg.bits.day      = PAL_DS1307_INT2BCD(TimePtr->tm_wday);
  PalDs1307_TimekeeperRegTemp.DateReg.bits.date    = PAL_DS1307_INT2BCD(TimePtr->tm_mday);
  /* DS1307 represents month as ordinal number but time.h's tm struct does not */
  PalDs1307_TimekeeperRegTemp.MonthReg.bits.month  = PAL_DS1307_INT2BCD(TimePtr->tm_mon);
  PalDs1307_TimekeeperRegTemp.YearReg              = PAL_DS1307_INT2BCD(TimePtr->tm_year);
  PalDs1307_TimekeeperRegTemp.Reserved             = NULL;

  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(0x03);

  /* Stream data bytes on SDA line */
  putsI2C(&PalDs1307_TimekeeperRegTemp.DayReg.byte);

  /* Send Stop command */
  StopI2C();

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 25, 2012, 1:26:04 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_GetTime (PalDs1307_BreakdownTimeType* TimePtr)
{
  Std_ReturnType retVal = E_NOT_OK;

  PalDs1307_TimekeeperRegType PalDs1307_TimekeeperRegTemp;

  /* ---- Dummy write ------------------------------------------------------- */
  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(0x00);

  /* ---- Actual read operation starts here --------------------------------- */
  /* Send restart command */
  RestartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address | I2C_READ_WRITE_MSK);

  /* Read data stream from SDA (Seconds, Minutes and Hours */
  getsI2C(&PalDs1307_TimekeeperRegTemp.SecondsReg.byte, 3);

  /* Send Stop command */
  StopI2C();

  if(_12_HOUR == PalDs1307_TimekeeperRegTemp.HoursReg.bits.mode)
    {
      set_PalDs1307_AmPm(PalDs1307_TimekeeperRegTemp.HoursReg.bits.ampm);
    }
  /* else not required [if(_12_HOUR == PalDs1307_TimekeeperRegTemp.HoursReg.bits.mode)] */

  TimePtr->tm_sec       = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.SecondsReg.bits.seconds);
  TimePtr->tm_min       = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.MinutesReg.bits.minutes);
  TimePtr->tm_hour      = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.HoursReg.bits.hours);

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in Ds1307.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 25, 2012, 1:57:55 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalDs1307_GetDate (PalDs1307_BreakdownTimeType* TimePtr)
{
  Std_ReturnType retVal = E_NOT_OK;

  PalDs1307_TimekeeperRegType PalDs1307_TimekeeperRegTemp;

  /* ---- Dummy write ------------------------------------------------------- */
  /* Wait till I2C bus is free */
  IdleI2C();

  /* Send start command */
  StartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address & ~I2C_READ_WRITE_MSK);

  /* Send data address */
  WriteI2C(0x03);

  /* ---- Actual read operation starts here --------------------------------- */
  /* Send restart command */
  RestartI2C();

  /* Send device address with Write command */
  WriteI2C(I2c_Ds1307Address | I2C_READ_WRITE_MSK);

  /* Read data stream from SDA (Day, Date, Month, Year */
  getsI2C(&PalDs1307_TimekeeperRegTemp.DayReg.byte, 4);

  /* Send Stop command */
  StopI2C();

  TimePtr->tm_wday      = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.DayReg.bits.day);
  TimePtr->tm_mday      = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.DateReg.bits.date);
  TimePtr->tm_mon       = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.MonthReg.bits.month);
  TimePtr->tm_yday      = PAL_DS1307_BCD2INT(PalDs1307_TimekeeperRegTemp.YearReg);

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */


/** END OF FILE ********************* Copyright (C) 2012 Afflatus Techtronics */
